技巧22 清除缓存

使用 --no-cache 标志通常足以解决在缓存方面遇到的任何问题。但是有时候往往需要的是一个更细粒度的解决方案。如果有一个构建需要花费很长时间,例如,用户可能想在某个点之前使用缓存,之后使其失效以便重新执行一条命令并创建一个新镜像。

问题

想要在Dockerfile构建中从一个指定的点开始让Docker构建缓存失效。

解决方案

在命令后面增加一条无害的注释,从而让缓存失效。

不妨从https://github.com/docker-in-practice/todo的Dockerfile开始上手(它对应下列输出里的每个 Step 行),我们已经完成了一次构建,并随后在 CMD 这一行上添加了一条注释。我们可以在这里看到再次执行 docker build 的输出:

$ docker build .   ⇽--- 一次“正常”的docker构建
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon
Step 0 : FROM node
 ---> 91cbcf796c2c
Step 1 : MAINTAINER ian.miell@gmail.com
 ---> Using cache
 ---> 8f5a8a3d9240
Step 2 : RUN git clone -q https://github.com/docker-in-practice/todo.git
 ---> Using cache
 ---> 48db97331aa2
Step 3 : WORKDIR todo
 ---> Using cache
 ---> c5c85db751d6
Step 4 : RUN npm install
 ---> Using cache
 ---> be943c45c55b
Step 5 : EXPOSE 8000
 ---> Using cache  ⇽--- 到这里为止均是使用的缓存
 ---> 805b18d28a65
Step 6 : CMD ["npm","start"] #bust the cache  ⇽--- 缓存不再有效了,但是该命令实际上没有变化
 ---> Running in fc6c4cd487ce
 ---> d66d9572115e  ⇽--- 一个新的镜像被创建
Removing intermediate container fc6c4cd487ce
Successfully built d66d9572115e

本技巧的原理在于Docker将非空的更改均当作一行新的命令来对待,因此缓存的镜像层便不会再被复用。

读者可能会感到疑惑(我们第一次看到Docker时也有同感),Docker的层是否可以在镜像之间迁移并且合并它们,就像它们是Git中的更改集一样。在Docker里,至少当前是不可能实现的。一个层被定义成仅仅是一个指定镜像的更改集。因此,一旦缓存被破坏了,构建里的命令就不能再复用它。

正因为如此,如果可以,建议最好将不太可能变动的命令放到更靠近Dockerfile开头的位置。

讨论

最初迭代一份Dockerfile时,把每一行单独的命令拆分到一个单独的层有助于加快迭代速度,因为用户可以选择性地重新运行部分流程,如上述代码中展示的那样,但是这并不太适用于产出一个精简的最终镜像的场景。在复杂度足够高的情况下构建镜像时,层的数量达到硬性限制的42个并非闻所未闻。为了缓解这一情况,一旦用户得到了一个满意的正常工作的构建结果,就应该看看技巧56里介绍的步骤,去创建一个生产就绪的镜像。

results matching ""

    No results matching ""